package com.smsc.headend.task.engine.handler.impl.firmware;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.SystemClock;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.smsc.headend.common.enums.DeviceType;
import com.smsc.headend.common.enums.errorcode.TaskExecuteErrorCode;
import com.smsc.headend.common.enums.errorcode.TaskHandlerErrorCode;
import com.smsc.headend.module.asset.entity.ComEntity;
import com.smsc.headend.module.data.enums.OperationGroup;
import com.smsc.headend.module.fwu.entity.FirmwareFile;
import com.smsc.headend.module.fwu.entity.LogFwUpgradeHis;
import com.smsc.headend.module.fwu.entity.TemplateFwUpgrade;
import com.smsc.headend.module.protocol.DeviceData;
import com.smsc.headend.module.protocol.cosem.bo.CosemData;
import com.smsc.headend.module.protocol.cosem.util.ByteUtils;
import com.smsc.headend.module.task.dto.AtomicTask;
import com.smsc.headend.module.task.dto.AtomicTaskState;
import com.smsc.headend.module.task.dto.Task;
import com.smsc.headend.task.engine.dao.TaskDAO;
import com.smsc.headend.task.engine.exception.UDISTaskHandlerException;
import com.smsc.headend.task.engine.handler.TaskHandler;
import com.smsc.headend.task.engine.mapper.FirmwareFileMapper;
import com.smsc.headend.task.engine.service.CosemXmlService;
import com.smsc.headend.task.engine.service.FeignAssetManagementService;
import com.smsc.headend.task.engine.service.firmware.FirmwareService;
import com.smsc.headend.task.engine.utils.TaskParamUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import java.nio.charset.Charset;
import java.util.Map;

/**
 * @author liangli
 * @date 2020/10/9
 */
@Slf4j
public class ReadImagesToActivateHandler implements TaskHandler {
    public static final String GET_IDENTIFIER_FAILED = "get identifier failed";
    @Autowired
    TaskDAO taskDAO;
    @Autowired
    FirmwareService firmwareService;
    @Autowired
    CosemXmlService cosemXmlService;
    @Autowired
    FeignAssetManagementService assetManagementService;
    @Value("#{T(java.lang.Integer).parseInt('${fwu.step.retryTimes:2}')}")
    Integer firmwareStepsRetry;
    TemplateFwUpgrade.TaskType taskType = TemplateFwUpgrade.TaskType.ImageActivation;

    @Override
    public int handle(Task task, AtomicTask atomicTask, DeviceData deviceData, String actionResult) throws UDISTaskHandlerException {
        if (!(deviceData instanceof CosemData)) {
            throw new UDISTaskHandlerException(TaskHandlerErrorCode.DEVICE_DATA_TYPE_NOT_SUPPORT.toString());
        }

        CosemData cosemData = (CosemData) deviceData;
        CosemData idCosemData = cosemData.getChildAt(0).getChildAt(1);
        if (idCosemData.getIsNull()) {
            log.error("ImageActivation: " + GET_IDENTIFIER_FAILED);
            firmwareService.saveFwuReport(task, atomicTask, -1, taskType, GET_IDENTIFIER_FAILED, null);
            return -1;
        }
        Map<String, Object> paramMap = getParameterMap(task, atomicTask);
        Long fwFileId = Convert.toLong(paramMap.get("fwFileId"));

        if (fwFileId == null) {
            firmwareService.saveFwuReport(task, atomicTask, -1, taskType,"task no firmware file id", null);
            throw new UDISTaskHandlerException(TaskHandlerErrorCode.FW_FILE_NOT_EXISTS.toString());
        }

        String identifier = (String) cosemXmlService.getData(idCosemData.getType(), idCosemData.getValue());
        identifier = new String(ByteUtils.hexStringToByte(identifier), Charset.forName("utf-8"));

        String firmwareFileIdentifier = firmwareService.getFirmwareIdentifier(fwFileId);
        if (firmwareFileIdentifier != null && firmwareFileIdentifier.trim().equalsIgnoreCase(identifier.trim())) {
            log.info("ImageActivation: image identifier verified {}", firmwareFileIdentifier);
            return 1;
        }
        log.error("ImageActivation: image identifier not match, {}, {}", firmwareFileIdentifier, identifier);
        firmwareService.saveFwuReport(task, atomicTask, -1, taskType,"image identifier not match", null);
        return -1;
    }

    @Override
    public int handleFailure(Task task, AtomicTask atomicTask, String message) {
        if (message.equalsIgnoreCase("build aa fail")
                || message.equals(TaskExecuteErrorCode.TASK_WAITING_CON_RESPONSE_OVERTIME.toString())
                || message.equals(TaskExecuteErrorCode.TASK_WAITING_CON_RESPONSE_OVERTIME.getErrorText())
        )  {
            AtomicTaskState atomicTaskState = taskDAO.hashGetAtomicTaskState(atomicTask.getAtomicTaskNo());
            if (atomicTaskState.getRetryTimes() >= firmwareStepsRetry) {
                log.error("read images to activate failed as retry times over");
                firmwareService.saveFwuReport(task, atomicTask, -1, taskType, StrUtil.format("read failed , {}", message), null);
                return -1;
            }
            atomicTaskState.setRetryTimes(atomicTaskState.getRetryTimes() + 1);
            return 0;
        }

        Map<String, Object> param = TaskParamUtils.getParameterMap(task, atomicTask);
        log.error("read images to activate failed:taskNo={}, param={}, msg:{}", task.getTaskNo(), JSONUtil.toJsonStr(param), message);
        firmwareService.saveFwuReport(task, atomicTask, -1, taskType, null, null);
        return -1;
    }
}
